package DataConverters.DataReaders.readersImpl.defaultDataReader;

import DataConverters.DataReaders.AbstractDataReader;
import DataConverters.interfaces.IConvertable;
import DataConverters.DataReaders.IDataReader;
import DataConverters.DataReaders.readersImpl.defaultDataReader.CharBuffer.CharBuffer;
import DataConverters.DataReaders.readersImpl.defaultDataReader.CharBuffer.EndOfBufferException;

import DataConverters.DataReaders.readersImpl.defaultDataReader.LineReader.LineReader;
import DataConverters.DataReaders.readersImpl.defaultDataReader.Parser.NumberParser;
import DataConverters.exceptions.DataReaderException;
import DataConverters.exceptions.MissingNumberColumn;

import common.gui.progress.IProgressItem;
import DataConverters.interfaces.dataformulaobject.impl.DefaultCellBuilder;
import DataConverters.interfaces.dataformulaobject.intefaces.Cell;
import DataConverters.interfaces.dataformulaobject.intefaces.CellBuilder;
import FileInformation.FileInformation;
import FileInformation.utils.EndOfLineType;
import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

/**
 * Created by IntelliJ IDEA.
 * User: Nobody
 * Date: 21.04.11
 * Time: 22:21
 * To change this template use File | Settings | File Templates.
 */
public class DefaultDataReader extends AbstractDataReader implements IDataReader {

    public final static int BUFFER_SIZE = 1000;
    public static final String DEFUALT_CHARSET = "ASCII";
    private final LineReader lineReader = new LineReader();
    private NumberParser numberParser;
    private boolean readTextLines = false;
    private final StringBuilder textContent = new StringBuilder();
    private int rowNumber = 0;
    private int lastRowNumber = 0;

    public DefaultDataReader(IProgressItem progressLabel, IConvertable source) {
        super(progressLabel, source);

    }

    public void parseFileContent(FileInformation file) throws IOException {
        numberParser = new NumberParser(file.getDataSeparatorProvider());
        read(file.getFile().toString(), DEFUALT_CHARSET, file.getColumns(), file.getEndLineType().LINUX, file.getLineStarter(), file.getFirstDataRowNumber(), file.getLines());
    }

    private boolean areTextLinesAlreadyRead() {
        return readTextLines;
    }

    void readFirstTextLines(CharBuffer buffer, EndOfLineType endOfLineType, int ignoreLines) throws EndOfBufferException {
        for (int i = 0; i < ignoreLines - 1; ++i) {
            textContent.append(lineReader.readLine(buffer, endOfLineType)).append("\n");
            readTextLines = true;
        }

    }

    void readFirstTextLines(String buffer, EndOfLineType endOfLineType, int ignoreLines) {
        for (int i = 0; i < ignoreLines - 1; ++i) {
            textContent.append(buffer).append("\n");
            readTextLines = true;
        }
    }

    private void readTextLine(String line) {
        textContent.append(line).append("\n");
    }

    private void updateProgressLabel(int readedPercent, int interval) {
        if (lastRowNumber + interval == rowNumber) {
            progressItem.readed(readedPercent);
            lastRowNumber = rowNumber;
        }
    }

    public void read(String inputFile, String charset, int columnSize, EndOfLineType endOfLineType, char textLineStarter, int ignoreLines, int lines) throws IOException {
        int interval = (lines > 10000 ? 1000 : 1);
        progressItem.setMaximum(lines);
        progressItem.beforeReading();
        File FILE = new File(inputFile);
        FileChannel fileChannel = new FileInputStream(FILE).getChannel();
        Charset decoder = Charset.forName(charset);

        ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());
        fileChannel.read(buffer);
        buffer.flip();
        java.nio.CharBuffer cb = decoder.decode(buffer);
        BufferedReader br = new BufferedReader(new CharArrayReader(cb.array()));
        String line;
        while ((line = br.readLine()) != null) {
            // checks whether are no read rows,
            //only if ignoreLines parameters is not 0
            if (!areTextLinesAlreadyRead() && ignoreLines == 0) {
                textContent.append(buffer).append("\n");
                --ignoreLines;
                if (ignoreLines <= 1) {
                    readTextLines = true;
                }
                continue;
            }

            if (line.length() == 0) {
                ++rowNumber;
                continue;
            } else if (!isTextLine(line, textLineStarter)) {
                try {
                    double[] numbers = numberParser.parseCharArrayToFloatArray(line, columnSize);
                    addParsedNumbersToReadNumbers(numbers);
                } catch (MissingNumberColumn ex) {
                    String message = "row " + rowNumber + " : " + ex.getMessage() + ". Entire row was ignored" + "\n";
                    warningMessages.addMessage(message);
                }
            } else {
                readTextLine(line);
            }
            ++rowNumber;
            updateProgressLabel(rowNumber, interval);
        }
        updateProgressLabel(lines, interval);
        progressItem.afterReading();
        br.close();
        fileChannel.close();
    }

    private boolean isTextLine(String line, char textLineStarter) {
        return textLineStarter != 0 && line.charAt(0) == textLineStarter;
    }

    private void addParsedNumbersToReadNumbers(double[] newNumbers) {
        CellBuilder builder = new DefaultCellBuilder();
        for (int i = 0; i < newNumbers.length; ++i) {
            Cell cell = builder.createNumberCell(i, rowNumber, newNumbers[i]);
            formulasList.add(cell);
        }

    }

    @Override
    public void read() throws DataReaderException {
        try {
            FileInformation fileInformation = (FileInformation) source;
            parseFileContent(fileInformation);

        } catch (IOException ex) {
            throw new DataReaderException(ex);
        }
    }
}
